"""
Flask基础API示例 - 展示如何使用工具包构建基础的Flask API
包含用户管理、认证、基础CRUD操作等功能
"""

from flask import Flask, request, jsonify, g
from flask_cors import CORS
from functools import wraps
import os
import sys
from datetime import datetime
from typing import Optional, Dict, Any

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python_backend_toolkit.database import (
    DatabaseSession, DatabaseConfig, BaseRepository, BaseService, get_db
)
from python_backend_toolkit.database.base import BaseModel
from python_backend_toolkit.auth import AuthService, JWTHandler, PasswordHandler
from python_backend_toolkit.auth.models import User, UserCreate, UserResponse
from python_backend_toolkit.cache import MemoryCache, cached
from python_backend_toolkit.logging import get_logger
from python_backend_toolkit.utils import EmailValidator, generate_uuid
from python_backend_toolkit.api.responses import SuccessResponse, ErrorResponse, CreatedResponse
from python_backend_toolkit.api.exceptions import APIException, ValidationError, NotFoundError, UnauthorizedError

from sqlalchemy import Column, String, Integer, Text, Boolean, DateTime
from sqlalchemy.orm import Session


# ============================================================================
# 数据库模型定义
# ============================================================================

class Article(BaseModel):
    """文章模型"""
    title = Column(String(200), nullable=False, index=True)
    content = Column(Text, nullable=False)
    author_id = Column(Integer, nullable=False, index=True)
    is_published = Column(Boolean, default=False, nullable=False)
    published_at = Column(DateTime, nullable=True)


# ============================================================================
# 仓储层
# ============================================================================

class ArticleRepository(BaseRepository[Article]):
    """文章仓储"""
    
    def get_published_articles(self, limit: int = 10, offset: int = 0):
        """获取已发布的文章"""
        return (
            self.db.query(self.model)
            .filter(self.model.is_published == True)
            .filter(self.model.is_active == True)
            .order_by(self.model.created_at.desc())
            .offset(offset)
            .limit(limit)
            .all()
        )
    
    def get_by_author(self, author_id: int):
        """根据作者获取文章"""
        return (
            self.db.query(self.model)
            .filter(self.model.author_id == author_id)
            .filter(self.model.is_active == True)
            .all()
        )


# ============================================================================
# 服务层
# ============================================================================

class ArticleService(BaseService[Article]):
    """文章服务"""
    
    def __init__(self, repository: ArticleRepository):
        super().__init__(repository)
        self.logger = get_logger("ArticleService")
    
    def create_article(self, title: str, content: str, author_id: int) -> Article:
        """创建文章"""
        article_data = {
            "title": title,
            "content": content,
            "author_id": author_id,
            "is_published": False
        }
        
        article = self.create(article_data)
        self.logger.info("Article created", article_id=article.id, author_id=author_id)
        return article
    
    def publish_article(self, article_id: int, author_id: int) -> Optional[Article]:
        """发布文章"""
        article = self.get_by_id_sync(article_id)
        if not article or article.author_id != author_id:
            return None
        
        updated_article = self.update(article_id, {
            "is_published": True,
            "published_at": datetime.utcnow()
        })
        
        if updated_article:
            self.logger.info("Article published", article_id=article_id)
        
        return updated_article
    
    @cached(expire=300, key_func=lambda self, limit, offset: f"published_articles:{limit}:{offset}")
    async def get_published_articles_cached(self, limit: int = 10, offset: int = 0):
        """获取已发布文章（带缓存）"""
        return self.repository.get_published_articles(limit, offset)


# ============================================================================
# Flask应用配置
# ============================================================================

def create_app() -> Flask:
    """创建Flask应用"""
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev-secret-key')
    
    # 启用CORS
    CORS(app)
    
    # 初始化数据库
    db_config = DatabaseConfig(
        database_url=os.getenv('DATABASE_URL', 'sqlite:///./flask_example.db')
    )
    db_session = DatabaseSession(db_config)
    db_session.create_tables()
    
    # 初始化缓存
    cache = MemoryCache()
    
    # 初始化日志
    logger = get_logger("FlaskApp")
    
    # 初始化认证服务
    auth_service = AuthService()
    jwt_handler = JWTHandler()
    
    # ========================================================================
    # 中间件和装饰器
    # ========================================================================
    
    @app.before_request
    def before_request():
        """请求前处理"""
        g.request_id = generate_uuid()
        g.start_time = datetime.utcnow()
        
        logger.info(
            "Request started",
            request_id=g.request_id,
            method=request.method,
            path=request.path,
            remote_addr=request.remote_addr
        )
    
    @app.after_request
    def after_request(response):
        """请求后处理"""
        duration = (datetime.utcnow() - g.start_time).total_seconds()
        
        logger.info(
            "Request completed",
            request_id=g.request_id,
            status_code=response.status_code,
            duration=duration
        )
        
        return response
    
    def require_auth(f):
        """认证装饰器"""
        @wraps(f)
        def decorated_function(*args, **kwargs):
            auth_header = request.headers.get('Authorization')
            if not auth_header or not auth_header.startswith('Bearer '):
                return jsonify(ErrorResponse.create(
                    message="Missing or invalid authorization header",
                    error_code="AUTH_REQUIRED"
                ).dict()), 401
            
            token = auth_header.split(' ')[1]
            try:
                payload = jwt_handler.decode_token(token)
                g.current_user_id = payload.get('sub')
                g.current_username = payload.get('username')
            except Exception as e:
                return jsonify(ErrorResponse.create(
                    message="Invalid token",
                    error_code="INVALID_TOKEN"
                ).dict()), 401
            
            return f(*args, **kwargs)
        return decorated_function
    
    def handle_api_exception(func):
        """API异常处理装饰器"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except APIException as e:
                logger.error("API Exception", error=str(e), request_id=g.request_id)
                return jsonify(e.to_dict()), e.status_code
            except Exception as e:
                logger.error("Unexpected error", error=str(e), request_id=g.request_id)
                return jsonify(ErrorResponse.create(
                    message="Internal server error",
                    error_code="INTERNAL_ERROR"
                ).dict()), 500
        return wrapper
    
    # ========================================================================
    # 认证相关路由
    # ========================================================================
    
    @app.route('/auth/register', methods=['POST'])
    @handle_api_exception
    def register():
        """用户注册"""
        data = request.get_json()
        if not data:
            raise ValidationError("Request body is required")
        
        # 验证必需字段
        required_fields = ['username', 'email', 'password']
        for field in required_fields:
            if field not in data:
                raise ValidationError(f"Field '{field}' is required")
        
        # 验证邮箱格式
        email_validator = EmailValidator()
        email_result = email_validator.validate(data['email'])
        if not email_result.is_valid:
            raise ValidationError(f"Invalid email: {', '.join(email_result.errors)}")
        
        with db_session.session_scope() as db:
            try:
                user_data = UserCreate(
                    username=data['username'],
                    email=data['email'],
                    password=data['password']
                )
                
                user = auth_service.create_user(user_data.dict(), db)
                
                response = CreatedResponse.create(
                    data=UserResponse.from_orm(user).dict(),
                    message="User registered successfully",
                    request_id=g.request_id
                )
                
                return jsonify(response.dict()), 201
                
            except Exception as e:
                if "UNIQUE constraint failed" in str(e):
                    raise ValidationError("Username or email already exists")
                raise
    
    @app.route('/auth/login', methods=['POST'])
    @handle_api_exception
    def login():
        """用户登录"""
        data = request.get_json()
        if not data:
            raise ValidationError("Request body is required")
        
        username = data.get('username')
        password = data.get('password')
        
        if not username or not password:
            raise ValidationError("Username and password are required")
        
        with db_session.session_scope() as db:
            token = auth_service.authenticate_user(username, password, db)
            
            if not token:
                raise UnauthorizedError("Invalid credentials")
            
            response = SuccessResponse.create(
                data=token.dict(),
                message="Login successful",
                request_id=g.request_id
            )
            
            return jsonify(response.dict())
    
    # ========================================================================
    # 文章相关路由
    # ========================================================================
    
    @app.route('/articles', methods=['GET'])
    @handle_api_exception
    def get_articles():
        """获取文章列表"""
        limit = min(int(request.args.get('limit', 10)), 100)
        offset = int(request.args.get('offset', 0))
        
        with db_session.session_scope() as db:
            article_repo = ArticleRepository(Article, db)
            articles = article_repo.get_published_articles(limit=limit, offset=offset)
            
            articles_data = []
            for article in articles:
                articles_data.append({
                    "id": article.id,
                    "title": article.title,
                    "content": article.content[:200] + "..." if len(article.content) > 200 else article.content,
                    "author_id": article.author_id,
                    "published_at": article.published_at.isoformat() if article.published_at else None,
                    "created_at": article.created_at.isoformat()
                })
            
            response = SuccessResponse.create(
                data=articles_data,
                message="Articles retrieved successfully",
                request_id=g.request_id
            )
            
            return jsonify(response.dict())
    
    @app.route('/articles/<int:article_id>', methods=['GET'])
    @handle_api_exception
    def get_article(article_id: int):
        """获取单篇文章"""
        with db_session.session_scope() as db:
            article_repo = ArticleRepository(Article, db)
            article = article_repo.get_by_id(article_id)
            
            if not article or not article.is_published:
                raise NotFoundError("Article not found")
            
            article_data = {
                "id": article.id,
                "title": article.title,
                "content": article.content,
                "author_id": article.author_id,
                "published_at": article.published_at.isoformat() if article.published_at else None,
                "created_at": article.created_at.isoformat(),
                "updated_at": article.updated_at.isoformat()
            }
            
            response = SuccessResponse.create(
                data=article_data,
                message="Article retrieved successfully",
                request_id=g.request_id
            )
            
            return jsonify(response.dict())
    
    @app.route('/articles', methods=['POST'])
    @require_auth
    @handle_api_exception
    def create_article():
        """创建文章"""
        data = request.get_json()
        if not data:
            raise ValidationError("Request body is required")
        
        title = data.get('title')
        content = data.get('content')
        
        if not title or not content:
            raise ValidationError("Title and content are required")
        
        with db_session.session_scope() as db:
            article_repo = ArticleRepository(Article, db)
            article_service = ArticleService(article_repo)
            
            article = article_service.create_article(
                title=title,
                content=content,
                author_id=g.current_user_id
            )
            
            article_data = {
                "id": article.id,
                "title": article.title,
                "content": article.content,
                "author_id": article.author_id,
                "is_published": article.is_published,
                "created_at": article.created_at.isoformat()
            }
            
            response = CreatedResponse.create(
                data=article_data,
                message="Article created successfully",
                request_id=g.request_id
            )
            
            return jsonify(response.dict()), 201
    
    @app.route('/articles/<int:article_id>/publish', methods=['POST'])
    @require_auth
    @handle_api_exception
    def publish_article(article_id: int):
        """发布文章"""
        with db_session.session_scope() as db:
            article_repo = ArticleRepository(Article, db)
            article_service = ArticleService(article_repo)
            
            article = article_service.publish_article(article_id, g.current_user_id)
            
            if not article:
                raise NotFoundError("Article not found or you don't have permission")
            
            article_data = {
                "id": article.id,
                "title": article.title,
                "is_published": article.is_published,
                "published_at": article.published_at.isoformat() if article.published_at else None
            }
            
            response = SuccessResponse.create(
                data=article_data,
                message="Article published successfully",
                request_id=g.request_id
            )
            
            return jsonify(response.dict())
    
    @app.route('/my/articles', methods=['GET'])
    @require_auth
    @handle_api_exception
    def get_my_articles():
        """获取我的文章"""
        with db_session.session_scope() as db:
            article_repo = ArticleRepository(Article, db)
            articles = article_repo.get_by_author(g.current_user_id)
            
            articles_data = []
            for article in articles:
                articles_data.append({
                    "id": article.id,
                    "title": article.title,
                    "content": article.content[:100] + "..." if len(article.content) > 100 else article.content,
                    "is_published": article.is_published,
                    "published_at": article.published_at.isoformat() if article.published_at else None,
                    "created_at": article.created_at.isoformat()
                })
            
            response = SuccessResponse.create(
                data=articles_data,
                message="My articles retrieved successfully",
                request_id=g.request_id
            )
            
            return jsonify(response.dict())
    
    # ========================================================================
    # 健康检查和信息路由
    # ========================================================================
    
    @app.route('/health', methods=['GET'])
    def health_check():
        """健康检查"""
        return jsonify({
            "status": "healthy",
            "timestamp": datetime.utcnow().isoformat(),
            "version": "1.0.0",
            "service": "Flask Basic API"
        })
    
    @app.route('/info', methods=['GET'])
    def app_info():
        """应用信息"""
        return jsonify({
            "name": "Flask Basic API Example",
            "version": "1.0.0",
            "description": "基于Python Backend Toolkit的Flask API示例",
            "endpoints": {
                "auth": ["/auth/register", "/auth/login"],
                "articles": ["/articles", "/articles/<id>", "/my/articles"],
                "system": ["/health", "/info"]
            }
        })
    
    return app


# ============================================================================
# 应用启动
# ============================================================================

if __name__ == '__main__':
    app = create_app()
    
    print("=" * 60)
    print("Flask Basic API Example")
    print("=" * 60)
    print("Available endpoints:")
    print("  POST /auth/register - 用户注册")
    print("  POST /auth/login - 用户登录")
    print("  GET  /articles - 获取文章列表")
    print("  GET  /articles/<id> - 获取单篇文章")
    print("  POST /articles - 创建文章 (需要认证)")
    print("  POST /articles/<id>/publish - 发布文章 (需要认证)")
    print("  GET  /my/articles - 获取我的文章 (需要认证)")
    print("  GET  /health - 健康检查")
    print("  GET  /info - 应用信息")
    print("=" * 60)
    
    app.run(
        host='0.0.0.0',
        port=5000,
        debug=True
    )